package m.server;

import m.server.web.WebHandler;
import m.system.RuntimeData;
import m.system.exception.MException;
import m.system.task.SystemTask;
import m.system.util.FileUtil;
import m.system.util.StringUtil;
import m.system.util.SystemUtil;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocketFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;

public class TcpServer {

    private static Thread server;
    /**
     * 开启服务  需配置端口
     */
    public static void start(int port) throws Exception {
        start(port,1024);
    }
    /**
     * 开启服务  需配置端口 列队数
     */
    public static void start(int port,int backlog) throws Exception {
        start(WebHandler.class,port,backlog);
    }
    public static <T extends ServerHandler> void start(Class<T> handlerClass,int port,int backlog) throws Exception {
        server=new Thread(new Server<>(handlerClass, port, backlog));
        server.start();
    }
    public static void stop(){
        if(null!=server) server.interrupt();
    }


    private static class Server <T extends ServerHandler> implements Runnable{
        private final Class<T> handlerClass;
        private final int port;
        private final int backlog;
        public Server(Class<T> handlerClass,int port,int backlog){
            this.handlerClass=handlerClass;
            this.port=port;
            this.backlog=backlog;
        }
        @Override
        public void run() {
            ServerSocket server = null;
            try {
                SSLContext ssl=getSslContext();
                if(null!=ssl){
                    SSLServerSocketFactory sslServerSocketFactory = ssl.getServerSocketFactory();
                    server = sslServerSocketFactory.createServerSocket(port, backlog);
                }else {
                    server = new ServerSocket(port, backlog);
                }
                SystemUtil.println("服务启动成功，端口：",port);
                SystemTask.setLogPrint();
                while (!Thread.currentThread().isInterrupted()) {
                    new Thread(handlerClass.getConstructor(Socket.class).newInstance(server.accept())).start();
                }
            } catch (Exception e) {
                SystemUtil.println("服务器运行异常：",e.getMessage());
            } finally{
                try{
                    if(server != null){
                        server.close();
                        SystemUtil.println("服务器已关闭");
                    }
                }catch(IOException ignored){}
            }
        }
        public static SSLContext getSslContext() throws Exception {
            String jksCert= RuntimeData.getJksCert();
            if(StringUtil.notSpace(jksCert)) {
                char[] passArray = RuntimeData.getJksPass().toCharArray();
                SSLContext sslContext = SSLContext.getInstance("TLSv1");
                KeyStore ks = KeyStore.getInstance("JKS");
                File file = null;
                //加载keytool 生成的文件
                if (FileUtil.existsRootFile(jksCert)) {
                    file = FileUtil.getRootFile(jksCert);
                } else if (FileUtil.existsClassFile(jksCert)) {
                    file = FileUtil.getClassFile(jksCert);
                } else {
                    throw new MException(jksCert + "文件不存在");
                }
                FileInputStream inputStream = new FileInputStream(file);
                ks.load(inputStream, passArray);
                KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
                kmf.init(ks, passArray);
                sslContext.init(kmf.getKeyManagers(), null, null);
                inputStream.close();
                return sslContext;
            }else{
                return null;
            }
        }

    }

}
